package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    //  如何利用es的客户端实现保存数据到es!
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumIndexRepository albumIndexRepository;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private SuggestIndexRepository suggestIndexRepository;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void upperAlbum(Long albumId) {
        //  优化点：改为异步多线程！
        //  给AlbumInfoIndex对象赋值；然后将其保存到索引库！
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        //  赋值：albumInfoIndex 属性值来自于不同的表; 这些表都在哪? tingshu_album 它又属于专辑微服务！
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            //  远程调用;
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            Assert.notNull(albumInfoResult, "专辑结果集不存在！");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑不存在！");
            //  属性拷贝：
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            //  获取属性与属性值信息;并赋值; 远程调用获取数据; album_attribute_value
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            //  声明一个集合;
            ArrayList<AttributeValueIndex> attributeValueIndexArrayList = new ArrayList<>();
            //  循环遍历获取属性Id 与 属性值Id 并赋值;
            for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
                //  创建对象
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                //  赋值;
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                attributeValueIndexArrayList.add(attributeValueIndex);
            }
            //  赋值数据;
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexArrayList);
            return albumInfo;
        }, threadPoolExecutor).exceptionally(throwable -> {
            log.error("远程调用失败！" + throwable.getMessage());
            //  默认返回数据
            return null;
        });

        //  视图中的id=三级分类Id; 通过三级分类Id查找视图;
        CompletableFuture<Integer> categoryCompletableFuture = albumInfoCompletableFuture.thenApplyAsync(albumInfo -> {
            //  远程调用;
            Result<BaseCategoryView> baseCategoryViewResult = categoryFeignClient.getBaseCategoryViewByCategoryId(albumInfo.getCategory3Id());
            Assert.notNull(baseCategoryViewResult, "视图结果集不存在！");
            BaseCategoryView baseCategoryView = baseCategoryViewResult.getData();
            Assert.notNull(baseCategoryView, "视图不存在！");
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            //  1表示执行成功;
            return 1;
        }, threadPoolExecutor).exceptionally(throwable -> {
            log.error("远程调用失败！" + throwable.getMessage());
            //  默认返回数据
            return 0;
        });

        CompletableFuture<Integer> userCompletableFuture = albumInfoCompletableFuture.thenApplyAsync(albumInfo -> {
            //  获取用户信息：
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(albumInfo.getUserId());
            Assert.notNull(userInfoVoResult, "用户信息结果集不存在！");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo, "用户信息不存在！");
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
            //  专辑统计信息; 根据专辑Id 查询专辑的统计信息; album_stat
            albumInfoIndex.setPlayStatNum(new Random().nextInt(1000));
            albumInfoIndex.setCommentStatNum(new Random().nextInt(100));
            albumInfoIndex.setSubscribeStatNum(new Random().nextInt(100000));
            albumInfoIndex.setBuyStatNum(new Random().nextInt(100000));
            albumInfoIndex.setHotScore(new Random().nextDouble(1000));
            return 1;
        }, threadPoolExecutor).exceptionally(throwable -> {
            log.error("远程调用失败！" + throwable.getMessage());
            return 0;
        });
        //  异常处理!
        try {
            if (null == albumInfoCompletableFuture.get() || 0 == categoryCompletableFuture.get() || 0 == userCompletableFuture.get()) {
                throw new GuiguException(808, "专辑信息不存在！");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        //  多任务组合:
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                categoryCompletableFuture,
                userCompletableFuture
        ).join();
        //  保存：
        albumIndexRepository.save(albumInfoIndex);

        //  将提词库中的属性赋值; 标题;
        SuggestIndex suggestIndexTitle = new SuggestIndex();
        suggestIndexTitle.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndexTitle.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndexTitle.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndexTitle.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndexTitle.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        suggestIndexRepository.save(suggestIndexTitle);
        //  赋值专辑简介;
        SuggestIndex suggestIndexAlbumIntro = new SuggestIndex();
        suggestIndexAlbumIntro.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndexAlbumIntro.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndexAlbumIntro.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndexAlbumIntro.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        suggestIndexAlbumIntro.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        suggestIndexRepository.save(suggestIndexAlbumIntro);
        //  作者;
        //        SuggestIndex suggestIndexAnnouncerName = new SuggestIndex();
        //        suggestIndexRepository.save(suggestIndexAnnouncerName);


    }

    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String rankingDimension) {
        //  hget key field value;
        return (List<AlbumInfoIndex>) redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX+category1Id,rankingDimension);
    }

    @Override
    public void updateLatelyAlbumRanking() {
        //  1.  通过dsl 语句查询到数据结果集；
        //  通过远程调用获取到所有一级分类Id;
        Result<List<BaseCategory1>> baseCategory1Result = categoryFeignClient.findAllCategory1();
        Assert.notNull(baseCategory1Result, "一级分类结果集为空");
        List<BaseCategory1> baseCategory1List = baseCategory1Result.getData();
        //  循环遍历;
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            //  每个一级分类Id下有五个维度;
            String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
            for (String rankingDimension : rankingDimensionArray) {
                //  获取到结果集;
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                                    .query(q -> q.term(t -> t.field("category1Id").value(baseCategory1.getId())))
                                    .sort(st -> st.field(fd -> fd.field(rankingDimension).order(SortOrder.Desc)))
                            ,
                            AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //  获取集合数据集合;
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                //  List<AlbumInfoIndex> albumInfoIndexList1 = searchResponse.hits().hits().stream().map(Hit::source).toList();
                //  2.  将结果集存储到redis中; hset key field value;
                this.redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX+baseCategory1.getId(),rankingDimension,albumInfoIndexList);
            }
        }
    }

    @Override
    public List<String> completeSuggest(String keyword) {
        //  编写dsl 语句;
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("suggestinfo")
                            .suggest(sg -> sg.suggesters("keyword-suggest",
                                            ss -> ss.prefix(keyword).completion(c -> c.field("keyword")
                                                    .skipDuplicates(true)
                                                    .fuzzy(fz -> fz.fuzziness("auto"))
                                                    .size(10)
                                            ))
                                    .suggesters("keywordPinyin-suggest",
                                            ss -> ss.prefix(keyword).completion(c -> c.field("keywordPinyin")
                                                    .skipDuplicates(true)
                                                    .fuzzy(fz -> fz.fuzziness("auto"))
                                                    .size(10)
                                            ))
                                    .suggesters("keywordSequence-suggest",
                                            ss -> ss.prefix(keyword).completion(c -> c.field("keywordSequence")
                                                    .skipDuplicates(true)
                                                    .fuzzy(fz -> fz.fuzziness("auto"))
                                                    .size(10)
                                            ))
                            )
                    ,
                    SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取执行结果集;
        List<String> list = new ArrayList<>();
        list.addAll(this.getCommonSuggest(searchResponse, "keyword-suggest"));
        list.addAll(this.getCommonSuggest(searchResponse, "keywordPinyin-suggest"));
        list.addAll(this.getCommonSuggest(searchResponse, "keywordSequence-suggest"));
        //  返回结果集
        return list;
    }

    /**
     * 获取提词结果集
     *
     * @param searchResponse
     * @param keyword
     * @return
     */
    private Collection<String> getCommonSuggest(SearchResponse<SuggestIndex> searchResponse, String keyword) {
        //  searchResponse 获取keywrod对应的数据
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(keyword);
        List<String> list = suggestionList.get(0).completion().options().stream().map(option -> {
            //  获取数据对象
            SuggestIndex suggestIndex = option.source();
            return suggestIndex.getTitle();
        }).collect(Collectors.toList());
        //  返回数据
        return list;
    }

    @Override
    public List<Map<String, Object>> getChannel(Long category1Id) {
        //  获取到一级分类下的三级分类数据集合;
        Result<List<BaseCategory3>> baseCategory3ListResult = categoryFeignClient.findTopBaseCategory3(category1Id);
        //  获取数据并判断：
        Assert.notNull(baseCategory3ListResult, "一级分类下的三级分类数据集合不存在！");
        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
        Assert.notNull(baseCategory3List, "一级分类下的三级分类数据不存在！");
        //  将 baseCategory3List 集合转换为Map 集合; key=category3Id; value=category3;
        Map<Long, BaseCategory3> category3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        //  通过baseCategory3List 这个集合就能知道三级分类Id都有谁！ 1018,1019,1020,1021,1022,1023,1024
        //  根据三级分类Id查询专辑列表;
        List<FieldValue> valueList = baseCategory3List.stream().map(category3 -> {
            //  返回数据
            return FieldValue.of(category3.getId());
        }).collect(Collectors.toList());
        //  调用es客户端查询数据： ts.value(); 需要List<FieldValue>集合;  List<Long>转换为List<FieldValue>
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id").terms(ts -> ts.value(valueList))))
                            .aggregations("groupByCategory3IdAgg", a -> a.terms(t -> t.field("category3Id"))
                                    .aggregations("topSixHotScoreAgg", ag -> ag.topHits(th -> th.size(6)
                                            .sort(st -> st.field(f -> f.field("hotScore").order(SortOrder.Desc)))))
                            )
                    ,
                    AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取数据：
        Aggregate aggregate = searchResponse.aggregations().get("groupByCategory3IdAgg");
        List<Map<String, Object>> mapList = aggregate.lterms().buckets().array().stream().map(bucket -> {
            //  获取三级分类Id;
            long category3Id = bucket.key();
            //  创建map 集合数据：
            Map<String, Object> map = new HashMap<>();
            //  存储专辑集合列表：从这个聚合中获取 topSixHotScoreAgg
            Aggregate topSixHotScoreAgg = bucket.aggregations().get("topSixHotScoreAgg");
            List<AlbumInfoIndex> albumInfoIndexList = topSixHotScoreAgg.topHits().hits().hits().stream().map(hit -> {
                //  获取到source 数据;
                String jsonStr = hit.source().toString();
                //  进行数据转换;
                AlbumInfoIndex albumInfoIndex = JSON.parseObject(jsonStr, AlbumInfoIndex.class);
                //  返回数据
                return albumInfoIndex;
            }).collect(Collectors.toList());
            //  存储key三级分类对象; 根据三级分类Id获取到三级分类对象;
            map.put("baseCategory3", category3Map.get(category3Id));
            //  将专辑集合数据添加到map中.
            map.put("list", albumInfoIndexList);
            //  返回map 集合;
            return map;
        }).collect(Collectors.toList());
        //  返回map 集合
        return mapList;
    }

    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //  构建DSL语句;
        SearchRequest searchRequest = this.queryBuiildDsl(albumIndexQuery);
        //  根据关键词检索数据：
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  创建对象并赋值 这个方法中要给 List<AlbumInfoIndexVo> list 这个属性赋值;
        AlbumSearchResponseVo albumSearchResponseVo = this.parseResultData(searchResponse);
        /*
            private List<AlbumInfoIndexVo> list = new ArrayList<>();
            private Long total;//总记录数
            private Integer pageSize;//每页显示的内容
            private Integer pageNo;//当前页面
            private Long totalPages;
         */
        albumSearchResponseVo.setTotal(searchResponse.hits().total().value());
        //  每页显示的条数
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        //  当前第几页
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        //  总页数 10 3 4 | 9 3 3
        //  albumSearchResponseVo.setTotalPages(albumSearchResponseVo.getTotal() % albumSearchResponseVo.getPageSize() == 0 ? albumSearchResponseVo.getTotal() / albumSearchResponseVo.getPageSize() : albumSearchResponseVo.getTotal() / albumSearchResponseVo.getPageSize() + 1);
        albumSearchResponseVo.setTotalPages((albumSearchResponseVo.getTotal() + albumSearchResponseVo.getPageSize() - 1) / albumSearchResponseVo.getPageSize());
        //  返回数据
        return albumSearchResponseVo;
    }

    private SearchRequest queryBuiildDsl(AlbumIndexQuery albumIndexQuery) {
        //  创建对象
        //  获取了对象 SearchRequest 这个对象不能new :  因为构造器私有化! SearchRequest 这个类中有一个 静态 Builder 类, 在这个类中有一个build() 方法返回 SearchRequest
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        //  声明一个 Query 对象; 使用 boolQuery 承接多条件查询！
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
        //  设置索引库;
        searchRequestBuilder.index("albuminfo");
        //  有两个入口：
        //  第一个入口根据关键词检索
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            //  query-->bool-->must-->match
            //  searchRequestBuilder.query(q->q.bool(b->b.must(m->m.match(mt->mt.field("albumTitle").query(albumIndexQuery.getKeyword())))));
            //  boolQueryBuilder.must(m -> m.match(mt -> mt.field("albumTitle").query(albumIndexQuery.getKeyword())));
            boolQueryBuilder.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("announcerName").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())))
            ;
            //  设置高亮字段;
            searchRequestBuilder.highlight(h -> h.fields("albumTitle", f -> f.preTags("<span style=color:red>").postTags("</span>")));
        }
        //  第二个入口：
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory3Id())) {
            //  bool-->filter-->term
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory2Id())) {
            //  bool-->filter-->term
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory1Id())) {
            //  bool-->filter-->term
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        //  处理属性与属性值过滤：必然属于第二次以后查询项;
        //  <属性id:属性值id>
        List<String> attributeList = albumIndexQuery.getAttributeList();
        //  判断是否存在
        if (!CollectionUtils.isEmpty(attributeList)) {
            //  循环遍历;
            for (String attribute : attributeList) {
                //  attribute=属性id:属性值id;
                String[] split = attribute.split(":");
                //  判断数据是否存在; 符合标准根式
                if (null != split && split.length == 2) {
                    //  获取到属性Id=split[0] ; 属性值Id=split[1]; 构建DSL 语句：  属性id:属性值id 数据类型：Nested: 能够允许数据彼此独立的检索和查询！
                    boolQueryBuilder.filter(f -> f.nested(n -> n.path("attributeValueIndexList")
                            .query(qy -> qy.bool(b -> b.filter(ft -> ft.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
                                    .filter(ft -> ft.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))
                            ))
                    ));
                }
            }
        }
        //  排序： 综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc]；asc:升序 desc:降序）
        String order = albumIndexQuery.getOrder();
        //  判断排序字段是否为空
        if (!StringUtils.isEmpty(order)) {
            //  设置排序规则;
            String[] split = order.split(":");
            //  判断
            if (null != split && split.length == 2) {
                String filed = "";
                //  做判断根据什么字段排序
                switch (split[0]) {
                    case "1":
                        filed = "hotScore";
                        //  searchRequestBuilder.sort(s -> s.field(f -> f.field("hotScore").order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
                        break;
                    case "2":
                        filed = "playStatNum";
                        //  searchRequestBuilder.sort(s -> s.field(f -> f.field("playStatNum").order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
                        break;
                    case "3":
                        filed = "createTime";
                        //  searchRequestBuilder.sort(s -> s.field(f -> f.field("createTime").order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
                        break;
                }
                //  设置排序规则;
                String finalFiled = filed;
                searchRequestBuilder.sort(s -> s.field(f -> f.field(finalFiled).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }
        //  设置分页; from 表示从哪里开始?
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        searchRequestBuilder.from(from);
        //  设置默认值；
        searchRequestBuilder.size(albumIndexQuery.getPageSize());
        //  query-->bool
        searchRequestBuilder.query(boolQueryBuilder.build()._toQuery());
        //  构建对象
        SearchRequest searchRequest = searchRequestBuilder.build();
        //  dsl 语句是谁?searchRequest
        System.out.println("dsl:\t" + searchRequest.toString());
        //  有可能根据分类Id检索
        return searchRequest;
    }

    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        //  创建对象
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        /*
            private List<AlbumInfoIndexVo> list = new ArrayList<>();
         */
        List<AlbumInfoIndexVo> albumInfoIndexList = searchResponse.hits().hits().stream().map(hit -> {
            //  创建AlbumInfoIndexVo 对象
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            //  获取结果集中的数据;
            AlbumInfoIndex albumInfoIndex = hit.source();
            //  属性赋值;
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            //  判断是否有高亮数据显示;
            if (null != hit.highlight().get("albumTitle")) {
                //  获取高亮字段
                String albumTitle = hit.highlight().get("albumTitle").get(0);
                albumInfoIndexVo.setAlbumTitle(albumTitle);
            }
            //  返回数据
            return albumInfoIndexVo;
        }).collect(Collectors.toList());
        //  设置返回数据
        albumSearchResponseVo.setList(albumInfoIndexList);
        //  返回数据
        return albumSearchResponseVo;
    }

    @Override
    public void lowerAlbum(Long albumId) {
        //  下架;
        albumIndexRepository.deleteById(albumId);
    }
}
